package io.gitee.hejiang.action.impl;

import java.security.Principal;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NotAllowedException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;

import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;

import com.fasterxml.jackson.databind.JavaType;

import io.gitee.hejiang.action.SwaggerSqlAction;
import io.swagger.inflector.models.RequestContext;
import io.swagger.models.auth.SecuritySchemeDefinition;

public class KeycloakSecurityAction implements SwaggerSqlAction {
	SwaggerSqlAction _next;
	Map<String, SecuritySchemeDefinition> _schemes;
	List<Map<String, List<String>>> _security;
	boolean _enabled;

	public KeycloakSecurityAction(List<Map<String, List<String>>> security,
			Map<String, SecuritySchemeDefinition> schemes, boolean enabled) {
		_security = security;
		_schemes = schemes;
		_enabled = enabled;
	}

	@Override
	public void init(Map<String, Object> config, Map<String, JavaType> argumentTypes, SwaggerSqlAction next)
			throws Exception {
		_next = next;
	}

	@Override
	public Object execute(RequestContext request, Connection connection, Map<String, Object> arguments,
			Map<String, Object> context) throws Exception {
		// 进行安全过滤
		filter(request.getRequest(), request.getContext().getSecurityContext(), context);

		if (_next != null) {
			return _next.execute(request, connection, arguments, context);
		} else {
			return null;
		}
	}

	@SuppressWarnings("rawtypes")
	protected void filter(HttpServletRequest req, SecurityContext sc, Map<String, Object> context) {
		if (!_enabled || _security == null || _schemes == null) {
			return;
		}

		// 未登录
		Principal principal = sc.getUserPrincipal();
		if (principal == null) {
			throw new NotAuthorizedException(Response.status(Status.UNAUTHORIZED).build());
		}

		// 保存 principal 到上下文中
		context.put("_user_", principal.getName());

		for (Map<String, List<String>> auth : _security) {
			for (Map.Entry<String, List<String>> entry : auth.entrySet()) {
				// 无角色要求
				List<String> requiredRoles = entry.getValue();
				if (requiredRoles == null || requiredRoles.size() == 0) {
					return;
				}

				// keycloak
				if (principal instanceof KeycloakPrincipal) {
					KeycloakSecurityContext ksc = ((KeycloakPrincipal) principal).getKeycloakSecurityContext();
					if (ksc instanceof RefreshableKeycloakSecurityContext) {
						try {
							Set<String> roles = AdapterUtils
									.getRolesFromSecurityContext((RefreshableKeycloakSecurityContext) ksc);
							for (String role : requiredRoles) {
								if (roles.contains(role)) {
									return;
								}
							}
						} catch (Exception e) {
							throw new NotAllowedException("Not allowed", new String[] { "API" });
						}
						throw new NotAllowedException("Not allowed", new String[] { "API" });
					}
				}

				// other
				for (String role : requiredRoles) {
					if (req.isUserInRole(role)) {
						return;
					}
				}

				throw new NotAllowedException("Not allowed", new String[] { "API" });
			}
		}
	}
}
